import MetaTrader5 as mt5
import pandas as pd

from kbarutils.client_parse import client_parse
from kbarutils.kline_parse import kline_parse
import socket

class mql5_utils:
    """
    账号信息
    """

    r = socket.gethostbyname(socket.gethostname())
    exePath=""
    if r=="192.168.16.4":       #服务器IP
        exePath = "C:/software/mt5/terminal64.exe"
    else:
        exePath = "D:/MetaTrader5/terminal64.exe"

    account = 76185055
    password = "Dxw19950620"
    server = "Exness-MT5Trial5"

    """
    参数信息
    """
    barCount = 500  # 用于计算支撑阻力的k线
    barPriceOffset = 3  # 价格便宜，防止获取的高低点价格太近
    barMaxSize = 2000  # 返回最大k线数
    mParseK = kline_parse()
    mParseClient = client_parse()

    def login(self):
        """
        登录客户端
        """

        if mt5.account_info() is None:
            if not mt5.initialize(path=self.exePath):
                print("initialize() failed, error code =", mt5.last_error())
                quit()
                return False

            authorized = mt5.login(login=self.account, password=self.password, server=self.server)
            if authorized:
                print("connected to account #{}".format(self.account))
                return True
            else:
                print("failed to connect at account #{}, error code: {}".format(self.account, mt5.last_error()))
                return False
        return True

    def getBars(self, symbol, morethan=False,barSize=barCount):
        """
        获取k线
        symbol：交易品种
        morethan: 所有歷史數據均小于或大于当前价格时，是否继续获取更多历史数据
        """

        priceFrame5 = self.getBarPrice(symbol, mt5.TIMEFRAME_M5, morethan, barSize)
        priceFrame15 = self.getBarPrice(symbol, mt5.TIMEFRAME_M15, morethan, barSize)
        priceFrame30 = self.getBarPrice(symbol, mt5.TIMEFRAME_M30, morethan, barSize)
        priceFrame60 = self.getBarPrice(symbol, mt5.TIMEFRAME_H1, morethan, barSize)
        priceFrame240 = self.getBarPrice(symbol, mt5.TIMEFRAME_H4, morethan, barSize)
        priceFrameDay1 = self.getBarPrice(symbol, mt5.TIMEFRAME_D1, morethan, barSize)
        return [priceFrame5,priceFrame15, priceFrame30, priceFrame60, priceFrame240, priceFrameDay1]

    def resonate(self, kbarArr):
        """
        共振
        """
        sorted15Arr = kbarArr[0]["close"].to_list()
        sorted30Arr = kbarArr[1]["close"].to_list()
        sorted60Arr = kbarArr[2]["close"].to_list()
        sorted240Arr = kbarArr[3]["close"].to_list()

        sorted15Arr.reverse()
        sorted30Arr.reverse()
        sorted60Arr.reverse()
        sorted240Arr.reverse()
        return self.mParseK.beatTogether(sorted15Arr, sorted30Arr, sorted60Arr, sorted240Arr)

    def continuity(self, kbarArr):
        """
        k线连续性
        """
        return self.mParseK.continuity(self.paramArr(kbarArr))

    def bollingerStatus(self, kbarArr, currentPrice):
        """
        布林线状态
        """
        return self.mParseK.bollingerBands(self.paramArr(kbarArr), currentPrice=currentPrice)

    def noticeCheck(self, resonate, deviate, support, currentParice, continuity, bollinger, bollingerCenterArr):
        """
        警报检测
        """
        noticeValue, orderStatus = self.mParseClient.checkNotice(resonate, deviate, support, currentParice, continuity,
                                                                 bollinger,
                                                                 bollingerCenterArr)
        if orderStatus != None:
            self.sendOrder(status=orderStatus, symbol="XAUUSDm")
        return noticeValue

    def paramArr(self, kbarArr):
        """
        参数复用
        """
        close15Arr = kbarArr[0]["close"].to_list()
        open15Arr = kbarArr[0]["open"].to_list()
        high15Arr = kbarArr[0]["high"].to_list()
        low15Arr = kbarArr[0]["low"].to_list()

        close30Arr = kbarArr[1]["close"].to_list()
        open30Arr = kbarArr[1]["open"].to_list()
        high30Arr = kbarArr[1]["high"].to_list()
        low30Arr = kbarArr[1]["low"].to_list()

        close60Arr = kbarArr[2]["close"].to_list()
        open60Arr = kbarArr[2]["open"].to_list()
        high60Arr = kbarArr[2]["high"].to_list()
        low60Arr = kbarArr[2]["low"].to_list()

        close240Arr = kbarArr[3]["close"].to_list()
        open240Arr = kbarArr[3]["open"].to_list()
        high240Arr = kbarArr[3]["high"].to_list()
        low240Arr = kbarArr[3]["low"].to_list()

        high15Arr.reverse()
        low15Arr.reverse()
        open15Arr.reverse()
        close15Arr.reverse()

        high30Arr.reverse()
        low30Arr.reverse()
        open30Arr.reverse()
        close30Arr.reverse()

        high60Arr.reverse()
        low60Arr.reverse()
        open60Arr.reverse()
        close60Arr.reverse()

        high240Arr.reverse()
        low240Arr.reverse()
        open240Arr.reverse()
        close240Arr.reverse()
        return high15Arr, low15Arr, open15Arr, close15Arr, high30Arr, low30Arr, open30Arr, close30Arr, high60Arr, low60Arr, open60Arr, close60Arr, high240Arr, low240Arr, open240Arr, close240Arr

    def arrayFormat(self, stringArr):
        """
        数组转换
        """
        array = []
        if stringArr != "":
            strArr = stringArr.split(",")
            for index in strArr:
                if index != "":
                    array.append(float(index))

        sortedArr = sorted(list(set(array)), reverse=True)

        newArr = []
        for index in range(len(sortedArr) - 1):
            if len(newArr) == 0:
                newArr.append(sortedArr[index])
            else:
                for i in range(len(newArr)):
                    if newArr[i] - sortedArr[index] < 10:
                        break
                    elif i == len(newArr) - 1 and newArr[i] - sortedArr[index] >= 10:
                        newArr.append(sortedArr[index])
        newArr.append(sortedArr[-1])

        if newArr[-2] - newArr[-1] < 10:
            newArr.pop(-2)
        return newArr

    def dayPriceInfo(self, symbol):
        """
        获取日内开盘价和最高价
        """
        kValue = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_D1, 0, 1)
        frameValue = pd.DataFrame(kValue)
        highArr = frameValue["high"][0]
        openArr = frameValue["open"][0]
        return highArr, openArr

    def getBarPrice(self, symbol, time, morethan, barCount):
        """
        获取K线价格
        获取到支撑阻力，确保有大于和小于当前价格的值
        """

        if not mt5.initialize():
            print("initialize() failed, error code =",mt5.last_error())
            quit()
            return
        kValue = mt5.copy_rates_from_pos(symbol,time, 1, barCount)
        frameValue = pd.DataFrame(kValue)

        if morethan==False or frameValue.size>self.barMaxSize:
            return frameValue

        highArr = frameValue["high"].to_list()
        lowArr = frameValue["low"].to_list()

        lastHigh=highArr[-1]
        lastLow=lowArr[-1]

        for i in range(len(lowArr) - 2, -1, -1):    #下降趋势
            if highArr[i] > lastLow:
                if i==0:
                    return self.getBarPrice(symbol, time, True, barCount * 2)
            else:
                break
        
        for i in range(len(highArr) - 2, -1, -1):   #上涨趋势
            if lowArr[i]<lastHigh:
                if i==0:
                    return self.getBarPrice(symbol, time, True, barCount * 2)
            else:
                break
        return frameValue


    def getCurrentInfo(self, symbol=""):
        """
        获取当前价格信息
        """
        return mt5.symbol_info(symbol)

    def getClientInfo(self):
        """
        获取客户端信息
        """
        return mt5.terminal_info()

    def getPositionsTotal(self):
        """
        获取当前持仓数量
        """
        return mt5.positions_total()
